/**
 * Copyright (C) 2010 - 2013 Harry Glasgow
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.googlecode.jaden.engine;

import com.googlecode.jaden.common.config.LayerConfig;
import com.googlecode.jaden.common.enums.LayerType;

import java.io.Serializable;

public class Layer implements Serializable {

    private static final long serialVersionUID = 100;

    private final LayerType layerType;
    private final double[][] weights; // [thisLayerWidth][precedingLayerWidth]
    private final double[] biases; // [thisLayerWidth]

    public Layer(LayerConfig layerConfig, int precedingLayerWidth) {
        biases = new double[layerConfig.getLayerWidth()];
        layerType = layerConfig.getLayerType();
        weights = new double[layerConfig.getLayerWidth()][precedingLayerWidth];
    }

    public Layer(LayerType layerType, double[][] weights, double[] biases) {
        if (biases.length != weights.length) {
            throw new IllegalStateException("Weights and biases are different sizes " + biases.length + ' ' +
                    weights.length);
        }
        this.layerType = layerType;
        this.biases = biases;
        this.weights = weights;
    }

    public void jog() {
        for (int i = 0; i < weights.length; i++) {
            for (int j = 0; j < weights[i].length; j++) {
                weights[i][j] *= 1 + Math.random() / 10 - Math.random() / 10;
            }
        }
        for (int i = 0; i < biases.length; i++) {
            biases[i] *= 1 + Math.random() / 10 - Math.random() / 10;
        }
    }

    public void reset() {
        for (int i = 0; i < weights.length; i++) {
            for (int j = 0; j < weights[i].length; j++) {
                weights[i][j] = Math.random() - Math.random();
            }
        }
        for (int i = 0; i < biases.length; i++) {
            biases[i] = Math.random() - Math.random();
        }
    }

    public LayerType getLayerType() {
        return layerType;
    }

    public int getLayerWidth() {
        return biases.length;
    }

    public double[] getBiases() {
        return biases;
    }

    public double[][] getWeights() {
        return weights;
    }
}
